﻿using System;
using System.Collections.Generic;

namespace IniFileManager
{
	/// <summary>
	/// Abstract class represents elements. Elements are values of properties.
	/// </summary>
	public abstract class IniElement : IIniFileToken
	{
		/// <summary>
		/// Gets or sets value stored in element.
		/// </summary>
		abstract public object Value { get; set; }

		static internal IniReferenceElement CreateReferenceElementFromString( IniData data, string section, string property )
		{
			return new IniReferenceElement( data, section, property );
		}


		static internal IniElement CreateElementFromString( IniSection section, IniProperty property, int index, string value, IniSchema schema, IniLoadOptions loadOption )
		{
			Type type;
			try
			{
				type = schema.Sections[section.Name].Properties[property.Name].Elements[index].ValueType;
			}
			catch( KeyNotFoundException )
			{
				if( loadOption == IniLoadOptions.Strict )
				{
					throw new ArgumentException( "Element does not exists in schema." );
				}
				else
				{
					type = typeof( string );
				}
			}

			IniElement result;
			if( type == typeof( string ) )
			{
				result = IniStringElement.Parse( value );
			}
			else
			{
				if( type == typeof( bool ) )
				{
					result = IniBoolElement.Parse( value );
				}
				else
				{
					if( type == typeof( long ) )
					{
						result = IniSignedElement.Parse( value );
					}
					else
					{
						if( type == typeof( ulong ) )
						{
							result = IniUnsignedElement.Parse( value );
						}
						else
						{
							if( type == typeof( float ) )
							{
								result = IniFloatElement.Parse( value );
							}
							else
							{
								if( loadOption == IniLoadOptions.Strict )
								{
									throw new FormatException( "Property's " + property.Name + " in section " + section.Name + "element number " + index + " is not declared in schema." );
								}
								else
								{
									result = IniStringElement.Parse( value );
								}
							}
						}
					}
				}
			}

			if( schema.Sections[section.Name].Properties[property.Name].Elements[index].IsValueValidWithin( result.Value ) == false )
			{
				throw new FormatException( "Property's " + property.Name + " in section " + section.Name + "element number " + index + " is not valid." );
			}

			return result;
		}

		#region IIniFileToken Members

		/// <summary>
		/// Method which is used to writing self to ini file. 
		/// </summary>
		/// <returns>String which will be written to ini file.</returns>
		public virtual string WriteSelf()
		{
			return this.Value.ToString();
		}

		#endregion
	}
}
